/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * FrameApp.java
 *
 * Created on May 9, 2011, 9:37:35 PM
 */
package tds;

import java.io.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.swing.*;

/**
 *
 * @author cwhitela
 */
public class FrameApp extends javax.swing.JFrame {
	
	Twitter twitter;
	DateFormat df;
	
	
	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
	@SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        usernameField = new javax.swing.JTextField();
        getTimelineButton = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();
        rateLimitLabel = new javax.swing.JLabel();
        BatchUserButton = new javax.swing.JButton();
        DateFilterCheckbox = new javax.swing.JCheckBox();
        fromMonth = new javax.swing.JTextField();
        fromDay = new javax.swing.JTextField();
        fromYear = new javax.swing.JTextField();
        jLabel6 = new javax.swing.JLabel();
        toMonth = new javax.swing.JTextField();
        toDay = new javax.swing.JTextField();
        toYear = new javax.swing.JTextField();
        RateLimitRefreshButton = new javax.swing.JButton();
        saveLocField = new javax.swing.JTextField();
        saveLocBrowseButton = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        jPanel2 = new javax.swing.JPanel();
        jLabel4 = new javax.swing.JLabel();
        SearchButton = new javax.swing.JButton();
        searchSubjectField = new javax.swing.JTextField();
        jLabel5 = new javax.swing.JLabel();
        SearchResultTypeSelector = new javax.swing.JComboBox();
        monitorButton = new javax.swing.JButton();
        stopMonitorButton = new javax.swing.JButton();
        textPanel = new javax.swing.JPanel();
        jLabel7 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        statusPane = new javax.swing.JTextPane();
        jLabel8 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        errorPane = new javax.swing.JTextPane();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jLabel1.setText("Timeline");

        getTimelineButton.setText("Get Timeline");
        getTimelineButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                getTimelineButtonActionPerformed(evt);
            }
        });

        jLabel3.setText("Remaining Hits:");

        rateLimitLabel.setText("Unknown");

        BatchUserButton.setText("Get Timeline from batch user file");
        BatchUserButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                BatchUserButtonActionPerformed(evt);
            }
        });

        DateFilterCheckbox.setText("Filter by date");

        jLabel6.setText("to");

        RateLimitRefreshButton.setText("Refresh");
        RateLimitRefreshButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                RateLimitRefreshButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel3)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(rateLimitLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(RateLimitRefreshButton))
                    .addComponent(BatchUserButton)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
                                .addComponent(fromMonth, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(fromDay, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(fromYear))
                            .addComponent(DateFilterCheckbox, javax.swing.GroupLayout.Alignment.LEADING))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabel6)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(toMonth, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(toDay, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(toYear, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(usernameField, javax.swing.GroupLayout.PREFERRED_SIZE, 141, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(getTimelineButton)))
                .addGap(85, 85, 85))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel3)
                            .addComponent(rateLimitLabel))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(DateFilterCheckbox))
                    .addComponent(RateLimitRefreshButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(fromMonth, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(fromDay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(fromYear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel6)
                    .addComponent(toMonth, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(toDay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(toYear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 23, Short.MAX_VALUE)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(usernameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(getTimelineButton))
                .addGap(17, 17, 17)
                .addComponent(BatchUserButton)
                .addGap(24, 24, 24))
        );

        saveLocBrowseButton.setText("Browse");
        saveLocBrowseButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveLocBrowseButtonActionPerformed(evt);
            }
        });

        jLabel2.setText("Save Location");

        jLabel4.setText("Search");

        SearchButton.setText("Search");
        SearchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                SearchButtonActionPerformed(evt);
            }
        });

        jLabel5.setText("Subject");

        SearchResultTypeSelector.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Mixed (Popular + Recent)", "Popular", "Recent" }));

        monitorButton.setText("Monitor");
        monitorButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                monitorButtonActionPerformed(evt);
            }
        });

        stopMonitorButton.setText("Stop");
        stopMonitorButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopMonitorButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel4)
                    .addComponent(jLabel5))
                .addGap(24, 24, 24)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addComponent(monitorButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(stopMonitorButton))
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addComponent(searchSubjectField, javax.swing.GroupLayout.PREFERRED_SIZE, 139, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(SearchButton))
                    .addComponent(SearchResultTypeSelector, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(89, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel4)
                    .addComponent(SearchResultTypeSelector, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel5)
                    .addComponent(searchSubjectField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(SearchButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(monitorButton)
                    .addComponent(stopMonitorButton))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jLabel7.setText("Status Information");

        jScrollPane1.setViewportView(statusPane);

        jLabel8.setText("Error Log");

        jScrollPane2.setViewportView(errorPane);

        javax.swing.GroupLayout textPanelLayout = new javax.swing.GroupLayout(textPanel);
        textPanel.setLayout(textPanelLayout);
        textPanelLayout.setHorizontalGroup(
            textPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(textPanelLayout.createSequentialGroup()
                .addGroup(textPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(textPanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jLabel7))
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 188, Short.MAX_VALUE)
                    .addGroup(textPanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jLabel8))
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 188, Short.MAX_VALUE))
                .addContainerGap())
        );
        textPanelLayout.setVerticalGroup(
            textPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(textPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel7)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 152, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel8)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 155, Short.MAX_VALUE)
                .addContainerGap())
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addGap(18, 18, 18)
                        .addComponent(saveLocBrowseButton))
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, 0, 381, Short.MAX_VALUE)
                        .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(saveLocField, javax.swing.GroupLayout.Alignment.LEADING)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(textPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(textPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 21, Short.MAX_VALUE)
                        .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel2)
                            .addComponent(saveLocBrowseButton))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(saveLocField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

	private void getTimelineButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_getTimelineButtonActionPerformed

		Date from = null, to = null;
		// Convert date strings to date if necessary
		if (DateFilterCheckbox.isSelected())
		{
			String fromString = fromYear.getText() + "-" + fromMonth.getText() + "-" + fromDay.getText();
			String toString = toYear.getText() + "-" + toMonth.getText() + "-" + toDay.getText();
			try
			{
				from = df.parse(fromString);
				to = df.parse(toString);
			}
			catch (ParseException pe)
			{
				logErr(pe.getMessage());
			}
		}
		updateRateLimit();
		if (rl.getRemainingHits() < 1)
			JOptionPane.showMessageDialog(null, "Rate Limit has been exceeded.  This refreshes every hour.");
		else
		{
			String saveLocation = saveLocField.getText();
			String username = usernameField.getText();
			// Confirm directory field is not empty
			if (saveLocation.isEmpty()) {
					JOptionPane.showMessageDialog(null, "Please enter or browse for a save location");
			} else {
				// Confirm username field is not empty
				if (username.isEmpty()) {
						JOptionPane.showMessageDialog(this, "Please enter a username");
				} else {

					//Confirm username is alphanumeric
					if ( !username.matches("[\\w]+") )
					{
							JOptionPane.showMessageDialog(this, "Please enter a valid username");
					}

					else {
						//Confirm save location is valid, attempt to make new directory
						//JOptionPane.showMessageDialog(this, "Confirm Save Location\nConfirm username\nDownload Timeline");
						File directory = new File(saveLocField.getText() + File.separatorChar + mdf.getFormattedDateTimeString( Calendar.getInstance().getTime() ).replace(":", ".") + " " + username);
						if ( !directory.mkdir() )
								JOptionPane.showMessageDialog(rootPane, "Unable to create directory.\n" + directory.getAbsolutePath() + "\nPlease ensure the path is correct and try again.");
						else
						{
							File timelineFile = null;
							BufferedWriter timelineWriter = null;
							UserTimeline timeline = null;
							BufferedWriter mentionsWriter = null;
							File mentionsFile = null;
							try {
								// Create timeline File
								timelineFile = new File (directory.getAbsolutePath() + File.separatorChar + username + ".txt");
								timelineFile.createNewFile();
								timelineWriter = new BufferedWriter(new FileWriter( timelineFile ));

								//Create mentions file
								mentionsFile = new File (directory.getCanonicalPath() + File.separatorChar + "mentions.txt");
								mentionsFile.createNewFile();
								mentionsWriter = new BufferedWriter( new FileWriter (mentionsFile));


								// Get timeline
								logOut("Timeline: " + username + " . . . ");
								try
								{
									timeline = twitter.getUserTimeline(username, from, to);
									
									// Write the timeline
									logOut("\tWriting " + timeline.tweets().size() + " tweets.");
									twitter.writeTweets(timelineWriter, timeline.tweets());
									// Write mentions
									twitter.writeMentions(mentionsWriter, twitter.getMentionsAndRetweets(timeline.tweets()));
								}
								catch (NoSuchUserException e)
								{
									logErr(e.getMessage());
								}
								catch (ProtectedUserException pue)
								{
									logErr(pue.getMessage());
								}
								
								updateRateLimit();

								

							}
							catch (IOException e)
							{
								logErr(e.getMessage());
							}
							catch (RateLimitException e)
							{
								updateRateLimit();
										
								while (rl.getRemainingHits() < 1) {
									DateFormat format = DateFormat.getDateInstance();
									Date now = new Date();
									Date reset = null;
									try {
										reset = format.parse(rl.getResetTime());
									}
									catch (ParseException pe)
									{
										logErr(pe.getMessage());
									}
									if (reset != null)
									{
										logOut("Waiting for rate limit to be reset at " + rl.getResetTime());
										while ( now.before(reset) )
										{
											try { Thread.sleep(10000); } catch (InterruptedException ie) {}
										}
										break;
									}
								}
							}
							finally
							{
								try
								{
									if (timelineWriter != null)
									{
										timelineWriter.flush();
										timelineWriter.close();
									}

									if (mentionsWriter != null)
									{
										mentionsWriter.flush();
										mentionsWriter.close();
									}

								}
								catch (IOException e) {	}
							}
						}
					}
				}
			}
        }
            
            

	}//GEN-LAST:event_getTimelineButtonActionPerformed

        private void saveLocBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveLocBrowseButtonActionPerformed

			JFileChooser chooser = new JFileChooser();
			chooser.setAcceptAllFileFilterUsed(false);
			chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

			File chosenFile = null;
			switch (chooser.showOpenDialog(this)) {
				case JFileChooser.APPROVE_OPTION:
					chosenFile = chooser.getSelectedFile();
					saveLocField.setText(chosenFile.getAbsolutePath());
					break;
				case JFileChooser.CANCEL_OPTION:
					JOptionPane.showMessageDialog(this, "Operation canceled.");
					break;
				case JFileChooser.ERROR_OPTION:
					JOptionPane.showMessageDialog(this, "An error occured with the browse dialog.\nPlease try again.");
					break;
				default:
					JOptionPane.showMessageDialog(this, "An unknown error occurred.");
			}

			//JOptionPane.showMessageDialog(null, usernameField.getText().isEmpty() ? "yes" : "no");

        }//GEN-LAST:event_saveLocBrowseButtonActionPerformed

		private void BatchUserButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_BatchUserButtonActionPerformed
        
			Date from = null, to = null;
		// Convert date strings to date if necessary
			if (DateFilterCheckbox.isSelected())
			{
				String fromString = fromYear.getText() + "-" + fromMonth.getText() + "-" + fromDay.getText();
				String toString = toYear.getText() + "-" + toMonth.getText() + "-" + toDay.getText();
				try
				{
					from = df.parse(fromString);
					to = df.parse(toString);
				}
				catch (ParseException pe)
				{
					logErr(pe.getMessage());
				}
			}
			updateRateLimit();
			if (rl.getRemainingHits() < 1)
				JOptionPane.showMessageDialog(null, "Rate Limit has been exceeded.  This refreshes every hour.");
			else
			{
				String saveLocation = saveLocField.getText();
				Collection<String> usernames = new ArrayList();


				// Confirm directory field is not empty
				if (saveLocation.isEmpty())
				{
						JOptionPane.showMessageDialog(null, "Please enter or browse for a save location");
				}
				else
				{
					try
					{
						// Make new directory
						File directory = new File(saveLocation + File.separatorChar + mdf.getFormattedDateTimeString( Calendar.getInstance().getTime() ).replace(":", ".") + " batch timeline");
						directory.mkdir();
						// Get user file (Seprated by newlines)
						File usernamesFile = null;
						JFileChooser chooser = new JFileChooser();
						switch (chooser.showOpenDialog(this)) 
						{
							case JFileChooser.APPROVE_OPTION:

								usernamesFile = chooser.getSelectedFile();
								BufferedReader reader = new BufferedReader(new FileReader(usernamesFile));

								for (String line = reader.readLine(); line != null; line = reader.readLine())
								{
									line = line.trim();
									if (line.matches(alphaNum))
										usernames.add(line);
								}

								for (String username : usernames)
								{
									updateRateLimit();
									
									BufferedWriter timelineWriter = new BufferedWriter(new FileWriter(new File(directory.getAbsolutePath() + File.separatorChar + username + ".txt")));
									BufferedWriter mentionsWriter = new BufferedWriter(new FileWriter(new File(directory.getAbsolutePath() + File.separatorChar + username + " mentions.txt")));
									UserTimeline timeline = null;
									try
									{
										logOut("Collecting timeline for " + username);
										timeline = twitter.getUserTimeline(username, from, to);
										logOut(timeline.tweets().size() + " tweets collected");
										twitter.writeTweets(timelineWriter, timeline.tweets());
										twitter.writeMentions(mentionsWriter, twitter.getMentionsAndRetweets(timeline.tweets()));
									}
									catch (RateLimitException e)
									{
										updateRateLimit();
										
										while (rl.getRemainingHits() < 1) {
											// example: Sat May 28 06:36:43 +0000 2011
											DateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZZ yyyy");
											Date reset = null;
											try {
												reset = format.parse(rl.getResetTime());
											}
											catch (ParseException pe) {
												logOut(pe.getMessage());
											 }
											if (reset != null)
											{
												logOut("Waiting for rate limit to be reset at " + rl.getResetTime());
												for (Date now = new Date(); now.before(reset) ; now = new Date())
												{
													try {
														Thread.sleep(10000);
													}
													catch (InterruptedException ie) {}
												}
												break;
											}
										}
									}
									catch (IOException e)
									{
										logErr(e.getMessage());
									}
									catch (ProtectedUserException e)
									{
										logErr(e.getMessage());
									}
									catch (NoSuchUserException e)
									{
										logErr(e.getMessage());
									}
								}

								break;
							case JFileChooser.CANCEL_OPTION:
								JOptionPane.showMessageDialog(this, "Operation canceled.");
								break;
							case JFileChooser.ERROR_OPTION:
								JOptionPane.showMessageDialog(this, "An error occured with the browse dialog.\nPlease try again.");
								break;
							default:
								JOptionPane.showMessageDialog(this, "An unknown error occurred.");
						}
					}
					catch (FileNotFoundException e)
					{
						JOptionPane.showMessageDialog(null, e.getMessage());
					}
					catch (IOException e)
					{
						JOptionPane.showMessageDialog(null, "IO Error occurred.");
					}
				}
			}
		}//GEN-LAST:event_BatchUserButtonActionPerformed

                private void RateLimitRefreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_RateLimitRefreshButtonActionPerformed
                    updateRateLimit();
                }//GEN-LAST:event_RateLimitRefreshButtonActionPerformed

				private void SearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SearchButtonActionPerformed
					try {
						if (validSearch()) {
							
							String q = searchSubjectField.getText();
							String location = saveLocField.getText() + File.separator + "tds_search " + mdf.getFormattedDateTimeString( Calendar.getInstance().getTime() ).replace(":", ".") + ".txt";
							BufferedWriter writer = new BufferedWriter(new FileWriter(new File(location)));
							SearchQuery s = new SearchQuery(q, getResultType());
							logOut("Searching for " + q);
							twitter.writeTweets(writer, twitter.search(s).getTweets());
							writer.flush();
							writer.close();
							logOut("Completed Search");
						}
					} catch (Exception e) {
						logErr(e.getMessage());
					} 
				}//GEN-LAST:event_SearchButtonActionPerformed

				private void monitorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_monitorButtonActionPerformed
					try {
						if (validSearch()) {
							String q = searchSubjectField.getText();
							String location = saveLocField.getText() + File.separator + "tds_search " + mdf.getFormattedDateTimeString( Calendar.getInstance().getTime() ).replace(":", ".") + ".txt";
							// Force recent
							SearchQuery s = new SearchQuery(q, SearchQuery.ResultType.recent);
							logOut("Monitoring Topic " + q);
							monitor = new SearchMonitor(s, location);
							monitor.start();
						}
					} catch (Exception e) {
						logErr(e.getMessage());
					}
					
				}//GEN-LAST:event_monitorButtonActionPerformed

				private void stopMonitorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopMonitorButtonActionPerformed
					if (monitor != null) {
						logOut("Stopping thread...");
						monitor.stop();
						logOut("Stopped.");
					}
				}//GEN-LAST:event_stopMonitorButtonActionPerformed

	/**
	 * @param args the command line arguments
	 */
	public static void main(String args[]) {
		java.awt.EventQueue.invokeLater(new Runnable() {

			public void run() {
				new FrameApp().setVisible(true);
			}
		});
	}
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton BatchUserButton;
    private javax.swing.JCheckBox DateFilterCheckbox;
    private javax.swing.JButton RateLimitRefreshButton;
    private javax.swing.JButton SearchButton;
    private javax.swing.JComboBox SearchResultTypeSelector;
    private javax.swing.JTextPane errorPane;
    private javax.swing.JTextField fromDay;
    private javax.swing.JTextField fromMonth;
    private javax.swing.JTextField fromYear;
    private javax.swing.JButton getTimelineButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JButton monitorButton;
    private javax.swing.JLabel rateLimitLabel;
    private javax.swing.JButton saveLocBrowseButton;
    private javax.swing.JTextField saveLocField;
    private javax.swing.JTextField searchSubjectField;
    private javax.swing.JTextPane statusPane;
    private javax.swing.JButton stopMonitorButton;
    private javax.swing.JPanel textPanel;
    private javax.swing.JTextField toDay;
    private javax.swing.JTextField toMonth;
    private javax.swing.JTextField toYear;
    private javax.swing.JTextField usernameField;
    // End of variables declaration//GEN-END:variables

	String status;
	MyDateFormatter mdf;
	String alphaNum = "[a-zA-Z0-9]+";
    RateLimitStatus rl;
	private SearchMonitor monitor;

	
	/** Creates new form FrameApp */
	public FrameApp() {
		initComponents();
		twitter = new Twitter();
		df = new SimpleDateFormat(Twitter.twitterDateFormatString);
		mdf = new MyDateFormatter();
        updateRateLimit();
		logOut("Ready.");
	}
	
	private SearchQuery.ResultType getResultType() {
		SearchQuery.ResultType type;
		
		switch (SearchResultTypeSelector.getSelectedIndex()) {
			case 0: type = SearchQuery.ResultType.mixed; break;
			case 1: type = SearchQuery.ResultType.popular; break;
			case 2: type = SearchQuery.ResultType.recent; break;
			default: type = null;
		}
		
		return type;
	}
	
	private boolean validSearch() {
		
		boolean valid = false;
		
		if (generalValid()) {
			if (searchSubjectField.getText().isEmpty()) {
				JOptionPane.showMessageDialog(fromMonth, "Please choose a search term");
			} else
				valid = true;
		}
	
		return valid;
	}
	
	private boolean generalValid() {
		
		boolean valid = false;
		
		if (rateLimitValid()) {
			if (saveLocValid())
				valid = true;
		}
		
		return valid;
	}
	
	private boolean rateLimitValid() {
		
		boolean valid = false;
		
		updateRateLimit();
		if (rl.getRemainingHits() < 1)
			JOptionPane.showMessageDialog(null, "Rate Limit has been exceeded.  This refreshes every hour.");
		else
			valid = true;
		
		return valid;
	}
	
	private boolean saveLocValid() {
				
		boolean valid = false;
		
		if (saveLocField.getText().isEmpty())
			JOptionPane.showMessageDialog(null, "Please enter or browse for a save location");
		else
			valid = true;
		
		return valid;
	}

	final public void updateRateLimit() {
		
		for (int count = 0; count >= 0; ++count)
		{
			try
			{
				rl = twitter.getRateLimit();
				break;
			}
			catch (IOException e)
			{
				if (count > 1)
				{
					break;
				}
			}
		}
		
		if (rl != null)
		{
			rateLimitLabel.setText( String.valueOf(rl.getRemainingHits()) );
		}
		else
		{
			rateLimitLabel.setText("Unknown");
		}
		
	}
        
	private String getFromDateString()
	{
		return buildDateString(fromMonth.getText(), fromDay.getText(), fromYear.getText());
	}

	private String getToDateString()
	{
		return buildDateString(toMonth.getText(), toDay.getText(), toYear.getText());
	}

	private String buildDateString(String month, String day, String year)
	{
		return year + "-" + month + "-" + day;
	}

	
	private void logOut(String string) {
		status = string;
		statusPane.setText(statusPane.getText() + string + "\n");
		System.out.println(string);
	}
	
	private void logErr(String string)
	{
		errorPane.setText(errorPane.getText() + string + "\n");
	}
}
